use std::io::prelude::*;
use std::io::{BufReader, SeekFrom};
use std::path::{Path, PathBuf};
+use std::sync::{Arc, Mutex};
use core::{Package, Target, Profile};
use util::{self, MTime};
/// `DependencyQueue`, but it also needs to be retained here because Cargo can
/// be interrupted while executing, losing the state of the `DependencyQueue`
/// graph.
-#[derive(Clone)]
-pub struct Fingerprint {
+pub type Fingerprint = Arc<FingerprintInner>;
+struct FingerprintInner {
extra: String,
deps: Vec<Fingerprint>,
local: LocalFingerprint,
+ resolved: Mutex<Option<String>>,
}
#[derive(Clone)]
MtimeBased(Option<MTime>, PathBuf),
}
-impl Fingerprint {
+impl FingerprintInner {
fn resolve(&self, force: bool) -> CargoResult<String> {
+ if !force {
+ if let Some(ref s) = *self.resolved.lock().unwrap() {
+ return Ok(s.clone())
+ }
+ }
let mut deps: Vec<_> = try!(self.deps.iter().map(|s| {
s.resolve(force)
}).collect());
try!(MTime::of(p)).to_string()
}
};
- debug!("inputs: {} {} {:?}", known, self.extra, deps);
- Ok(util::short_hash(&(known, &self.extra, &deps)))
+ let resolved = util::short_hash(&(&known, &self.extra, &deps));
+ debug!("inputs: {} {} {:?} => {}", known, self.extra, deps, resolved);
+ *self.resolved.lock().unwrap() = Some(resolved.clone());
+ Ok(resolved)
}
}
} else {
LocalFingerprint::Precalculated(try!(calculate_pkg_fingerprint(cx, pkg)))
};
- let fingerprint = Fingerprint {
+ let fingerprint = Arc::new(FingerprintInner {
extra: extra,
deps: deps,
local: local,
- };
+ resolved: Mutex::new(None),
+ });
cx.fingerprints.insert(key, fingerprint.clone());
Ok(fingerprint)
}
info!("fingerprint at: {}", loc.display());
let new_fingerprint = try!(calculate_build_cmd_fingerprint(cx, pkg));
- let new_fingerprint = Fingerprint {
+ let new_fingerprint = Arc::new(FingerprintInner {
extra: String::new(),
deps: Vec::new(),
local: LocalFingerprint::Precalculated(new_fingerprint),
- };
+ resolved: Mutex::new(None),
+ });
let is_fresh = try!(is_fresh(&loc, &new_fingerprint));
/// Given the data to build and write a fingerprint, generate some Work
/// instances to actually perform the necessary work.
-fn prepare(is_fresh: bool, loc: PathBuf, fingerprint: Fingerprint) -> Preparation {
+fn prepare(is_fresh: bool,
+ loc: PathBuf,
+ fingerprint: Fingerprint) -> Preparation {
let write_fingerprint = Work::new(move |_| {
debug!("write fingerprint: {}", loc.display());
let fingerprint = try!(fingerprint.resolve(true).chain_error(|| {